# @Time : 2024-10-25 15:08
# @Author : Fioman 
# @Phone : 13149920693
"""
属性描述符: 简单来说就是可以将对属性的访问,设置和删除通过函数的方式来实现,然后使用的时候又可以像属性那样
使用.就是一个属性访问控制的机制,允许在访问,修改和删除属性时自定义行为.
1) 通过装饰器@property @name.setter 语法来实现访问属性和修改属性
2) 通过属性描述符类(只要实现了 __get__(self,instance,owner),__set__(),__delete__ 这三个方法之一或者全部
     就称为属性描述符类
3) 使用property()函数定义类的属性访问方式,将方法转换为属性
property(fget=None,fset=None,fdel=None,doc=None):
fget：获取属性的函数（getter），即当访问属性时调用。
fset：设置属性的函数（setter），即当给属性赋值时调用。
fdel：删除属性的函数（deleter），即当删除属性时调用。
doc：属性的文档字符串
"""
import numbers


# region 1. 属性描述符通过装饰器 @property @name.setter 来实现
class Person:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):  # getter
        return self._name

    @name.setter
    def name(self, value: str):
        # 可以在设置name的时候做个判断,必须是字符串
        if isinstance(value, str):
            self._name = value
        else:
            # 如果传入的不是字符串,就抛出ValueError异常
            raise ValueError


p = Person("Fioman")
print(p.name)
p.name = "Bob"
print(p.name)


# 假如我赋值名字为100
# p.name = 100 # 出现异常
# endregion

# region 2. 自定义个描述符类,这个描述符类必须实现了__get__,__set__, __delete__方法中的一个或者全部
class ScoreDescriptor:
    def __init_(self, value: int):
        self.value = value

    def __get__(self, instance, owner):
        print("Getting", self.value)
        return self.value

    def __set__(self, instance, value):
        print("Setting", value)
        if isinstance(value, numbers.Integral):
            if 0 <= value <= 100:
                self.value = value
            else:
                raise ValueError

    def __delete__(self, instance):
        print("Deleting", self.value)
        del self.value


class MyClass:
    attribute = ScoreDescriptor()  # 使用描述符


obj = MyClass()
obj.attribute = 10
# obj.attribute = 101  # 报错
print(obj.attribute)


# endregion

# region 3. 使用property() 内置函数将方法转换为属性,从可以像访问属性的方式访问方法
class Person:
    def __init__(self, name):
        self._name = name

    def get_name(self):
        print('get_name被调用')
        return self._name

    def set_name(self, name):
        print("set_name 被调用")
        self._name = name

    def del_name(self):
        print("del_name 被调用")
        del self._name

    name = property(get_name, set_name, del_name, "The Person's Name")


p = Person("Fioman")
print(p.name)
p.name = "Bob"
del p.name

# endregion
